/*******************************************************************************************************************************
	
	 Agent Trader
	 
*******************************************************************************************************************************/	

/*******************************************************************************************************************************
	INITIAL BELIEFS
*******************************************************************************************************************************/	
//The name of the maintainer agent, and the timeout to use in communication with it.
maintainer(maintainer,2000). 

/*******************************************************************************************************************************
	INITIAL GOALS
*******************************************************************************************************************************/	
//These are just for testing purposes, an interesting testcase is presented, but adjust as you like.

!start.

+!start : .my_name(trader1) <- 
	!buy(item2, 0,4,1,2000,3,10000).
	
+!start : .my_name(trader2) <- 
		.wait(2000);
	!sell(item2, 4,50000).
	
+!start :  .my_name(trader3) <-
	.wait(2000);
	!sell(item2, 4,50000).
/*
+!start : .my_name(trader4) <- 
	!sell(item2, 4,50000).
	
+!start :  .my_name(trader5) <-
	!sell(item2, 4,50000).
	
+!start : .my_name(trader6) <- 
	!sell(item2, 4,50000).
	
+!start :  .my_name(trader7) <-
	!sell(item2, 4,50000).
	
+!start : .my_name(trader8) <- 
	!sell(item2, 4,50000).
	
+!start :  .my_name(trader9) <-
	!sell(item2, 4,50000).
	
+!start : .my_name(trader10) <- 
	!sell(item2, 4,50000).
*/

/*******************************************************************************************************************************
	 GOALS TRIGGERED
*******************************************************************************************************************************/	
	
/*******************************************************************************************************************************
	Buy 		: Attempts to buy an item from the market.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item to buy.
	MinPrice	: The price to start the auction with.
	MaxPrice 	: The maxiumum price to pay for the item.
	StepSize	: The amount by which the bid gets increased every round in an auction.
	AuctionRoundTimeout : The maximum time to wait on response in an auction round before continuing.
	MaxNrOfAuctions : The maximum number of auctions to organise, when attempting to buy this item.
	MaxTotalWaitingTime : The maximum time to wait in between auctions, when attempting to buy this item. 
	----------------------------------------------------------------------------------------------------------------------
	Beliefs added:
	buying(Item) : Indicates the agent is performing the goal buy, for an item. To prevent having two buy goals for the same item.
	buyInfo(Item,NrOfAuction,MaxTotalWaitingTime) : 
		Information about the buy goal, such as the Item, the current number of auction.
		And the total time to wait in between auctions. 
	continueBuy(Item) 	: Indicates whether the agent should continue the loop for buying an item, otherwise it is done.
	buyInfoTimeLeft(Item,TotalWaitingTime) : Indicates the time that is left before the MaTotalWaitingTime is expired.
*******************************************************************************************************************************/
+!buy(Item,MinPrice,MaxPrice,StepSize,AuctionRoundTimeout,MaxNrOfAuctions,MaxTotalWaitingTime) : maintainer(Maintainer,_) & not buying(Item) <-
	+buying(Item);
	.print("Buying Item(",Item,") MaxPrice(",MaxPrice,").");
	!registerAndMatchRequest(Item);
	+buyInfo(Item,0,MaxTotalWaitingTime);
	+continueBuy(Item);
	while(continueBuy(Item))
	{
		
		?buyInfo(Item,NrOfAuction,TotalWaitingTime);
		-buyInfo(Item,NrOfAuction,TotalWaitingTime)[source(self)];
		//When organising an auction for the second time, we wait till there is a new offer added.
		//Otherwise organising the auction with the same maxPrice etc. is no use.
		//Also guarantees there is at least 1 offer.
		if(NrOfAuction>0)
		{
			//wait for a new offer
			.wait({+matchingOfferAdded(Item,_)},TotalWaitingTime,EventTime);
			+buyInfoTimeLeft(Item,TotalWaitingTime - EventTime); //Substract the time waited from the MaxTotalWaitingTime.
		}
		else
		{
			//Wait till there is at least 1 seller, otherwise organising an auction is useless.
			.findall(X,matchingOffer(Item,X),NrOfSellers);
			if(NrOfSellers < 1)
			{
				.wait({+matchingOfferAdded(Item,_)},TotalWaitingTime,EventTime); 
				+buyInfoTimeLeft(Item,TotalWaitingTime - EventTime);  //Substract the time waited from the MaxTotalWaitingTime.
			}
			else
			{
				+buyInfoTimeLeft(Item,TotalWaitingTime);
			}
		}
		
		//retrieve time left
		?buyInfoTimeLeft(Item,TimeLeft);
		-buyInfoTimeLeft(Item,TimeLeft);
		//If maxWaitingTime is up, then fail the goal.
		if(TimeLeft < 1)
		{
			-continueBuy(Item)[source(self)];
			.print("MaxTotalWaitingTime Exceeded",TimeLeft);
		}
		//Organise Auction.
		!organiseAuction(Item,MinPrice,MaxPrice,StepSize,AuctionRoundTimeout);
		
		if(itemBought(Item,Seller,Price))
		{
			-continueBuy(Item)[source(self)];
			.print("Item bought for ",Price, " from ", Seller);
		}
		else
		{
			if(NrOfAuction+2>MaxNrOfAuctions)
			{
				-continueBuy(Item)[source(self)];
			}
			else
			{
				
				+buyInfo(Item,NrOfAuction+1,TimeLeft);
			}
		}
		
		
		
	}	
	!removeRequest(Item);
	//Remove beliefs.
	.abolish(buyInfo(Item,_,_));
	.abolish(buyInfoTimeLeft(Item,__));
	.abolish(matchingOffer(Item,_));
	.abolish(continueBuy(Item));
	-buying(Item)[source(self)].
	
-!buy(Item,MinPrice,MaxPrice,StepSize,AuctionRoundTimeout,MaxNrOfAuctions,MaxTotalWaitingTime) : maintainer(Maintainer,_) <-
	if(registeredRequest(Item)){!removeRequest(Item);}
	//remove beliefs
	.print("ABOliShing beliefs");
	.abolish(buyInfo(Item,_,_));
	.abolish(buyInfoTimeLeft(Item,__));
	-matchingOffer(Item,_)[source(self)];
	.abolish(continueBuy(Item));
	-buying(Item)[source(self)];
	.print("Unable to buy Item(",Item,") MaxPrice(",MaxPrice,").").

/*******************************************************************************************************************************
	Sell 		: Attempts to sell an item to the market.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item to buy.
	MinPrice	: The price to start the auction with.
	MaxTotalWaitingTime : The maximum time to wait before this item is sold. 
	----------------------------------------------------------------------------------------------------------------------
	Beliefs added:
	selling(Item,MinPrice)	: 	Indicates the agent is performing the sell goal for the specified item. With a minimal price
								to sell that item.
	
*******************************************************************************************************************************/
+!sell(Item,MinPrice,MaxTotalWaitingTime) : maintainer(Maintainer,_) <-
	+selling(Item,MinPrice);
	.print("Selling Item(",Item,") MinPrice(",MinPrice,").");
	!registerOffer(Item);
	.wait({+itemSold(Item,_,_)},MaxTotalWaitingTime);
	.print("Sold item ",Item);
	!removeOffer(Item);
	-selling(Item,MinPrice)[source(self)].

-!sell(Item,MinPrice,MaxTotalWaitingTime) : maintainer(Maintainer,_) <-
	if(registeredOffer(Item)){!removeOffer(Item);}
	-selling(Item,MinPrice)[source(self)];
	.print("Unable to sell: Item(",Item,") MinPrice(", MinPrice,").").


/*******************************************************************************************************************************
	RegisterAndMatchRequest : Registers a request by the maintainer, and expects matching offers back.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item to register.
	----------------------------------------------------------------------------------------------------------------------
	Beliefs added:
	registerAndMatchingRequest(Item):	Indicates the agent is registering the specified Item, and expects matching offers
										from the maintainer.
	matchingOffer(Item,Seller):			The seller of an offer that matches the request for specified Item.			
	registeredRequest(Item):			Indicates that the agent has succesfully registered a request by the maintainer for the item.	
*******************************************************************************************************************************/
+!registerAndMatchRequest(Item) : maintainer(Maintainer,Timeout) & not registeredRequest(Item) & not registeringRequest(Item) <-
	+registeringAndMatchingRequest(Item);
	.send(Maintainer,achieve,registerAndMatchRequest(Item));
	.wait({+registerAndMatchRequest(Item,_,_)[source(Maintainer)]},Timeout);
	?registerAndMatchRequest(Item,Sellers,Result)[source(Maintainer)];
	-registerAndMatchRequest(Item,_,Result)[source(Maintainer)];
	if(Result \== succeeded){.fail;};
	//Add sellers of offers that match to the belief base.
	for(.member(Seller,Sellers))
	{	
		+matchingOffer(Item,Seller);
	}
	+registeredRequest(Item);
	-registeringAndMatchingRequest(Item)[source(self)].
	
-!registerAndMatchRequest(Item) : maintainer(Maintainer,Timeout) & not registeredRequest(Item) <-
	-registeringRequest(Item)[source(self)];
	-registeredRequest(Item)[source(self)];
	.print("Failed to register request for Item (", Item, ").").

/*******************************************************************************************************************************
	RegisterOffer : Registers an offer by the maintainer.
	----------------------------------------------------------------------------------------------------------------------
	Parameters
	Item 		: The item to register.
	----------------------------------------------------------------------------------------------------------------------
	Beliefs added:
	registeringOffer(Item):	Indicates the agent is registering an offer.
	registeredOffer(Item):	Indicates that the agent has succesfully registered an offer by the maintainer for the item.
*******************************************************************************************************************************/
+!registerOffer(Item) : maintainer(Maintainer,Timeout) & not registeredOffer(Item) & not registeringOffer(Item) <-
	+registeringOffer(Item);
	.print("Registering Offer for Item (", Item, ") Timeout(",Timeout,").");
	.send(Maintainer,achieve,registerOffer(Item));
	.wait({+registerOffer(Item,_)[source(Maintainer)]},Timeout);
	?registerOffer(Item,Result)[source(Maintainer)];
	-registerOffer(Item,Result)[source(Maintainer)];
	if(Result \== succeeded){.fail;};
	+registeredOffer(Item);
	-registeringOffer(Item)[source(self)].

-!registerOffer(Item) : maintainer(Maintainer,Timeout) & not registeredOffer(Item)  <-
	-registeringOffer(Item)[source(self)];
	-registeredOffer(Item)[source(self)];
	.print("Failed to register offer for Item (", Item, ").").
	
/*******************************************************************************************************************************
	RemoveRequest : Removes a request that is registered by the maintainer.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item to remove.
	----------------------------------------------------------------------------------------------------------------------
	Beliefs added:
	removingRequest(Item):	Indicates the agent is removing a request.
	
*******************************************************************************************************************************/
+!removeRequest(Item) : maintainer(Maintainer,Timeout) & registeredRequest(Item) & not removingRequest(Item) <-
	+removingRequest(Item);
	.print("Removing Request for Item (", Item, ") Timeout(",Timeout,").");
	.send(Maintainer,achieve,removeRequest(Item));
	.wait({+removeRequest(Item,_)[source(Maintainer)]},Timeout);
	?removeRequest(Item,Result)[source(Maintainer)];
	-removeRequest(Item,Result)[source(Maintainer)];
	if(Result \== succeeded){.fail;};
	-registeredRequest(Item)[source(self)];
	-removingRequest(Item)[source(self)].
	
-!removeRequest(Item) : maintainer(Maintainer,Timeout) & registeredRequest(Item) <-
	-removingRequest(Item);
	.print("Failed to remove request for Item (", Item, ").").


/*******************************************************************************************************************************
	RemoveOffer : Removes an offer that is registered by the maintainer.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item to remove.
	----------------------------------------------------------------------------------------------------------------------
	Beliefs added:
	removingOffer(Item):	Indicates the agent is removing an offer.
*******************************************************************************************************************************/
+!removeOffer(Item) : maintainer(Maintainer,Timeout) & registeredOffer(Item) & not removingOffer(Item) <-
	+removingOffer(Item);
	.print("Removing Offer for Item (", Item, ") Timeout(",Timeout,")."); 
	.send(Maintainer,achieve,removeOffer(Item));
	.wait({+removeOffer(Item,_)[source(Maintainer)]},Timeout);
	?removeOffer(Item,Result)[source(Maintainer)]; 
	-removeOffer(Item,Result)[source(Maintainer)];
	if(Result \== succeeded){.fail;};
	-registeredOffer(Item)[source(self)];
	-removingOffer(Item)[source(self)].

-!removeRequest(Item) : maintainer(Maintainer,Timeout) & registeredOffer(Item) <-
	-removingOffer(Item)[source(self)];
	.print("Failed to remove offer for Item (", Item, ") Timeout(",Timeout,").").
	
/*******************************************************************************************************************************
	OrganiseAuction : Organises an auction with this agent as buyer and multiple other sellers.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item to auction.
	MinPrice 	: The price to start the auction at.
	MaxPrice 	: The maximal price this agent is willing to pay for the item.
	StepSize	: The amount by which the bid gets increased every round.
	RoundTimeout: The maximum time to wait on response in an auction round before continuing.
	----------------------------------------------------------------------------------------------------------------------
	Beliefs added:
	organisingAuction(Item):	Indicates the agent is performing the organisingAuction goal for specified Item.
	auctionInfo(Item,BidPrice,RoundNr,PreviousSeller):	Holds information about the state of an auction.
	continueAuction(Item):		Indicates wether the agent should continue the auction.
	sendConfirmAgreementAgree(Item,Price): Indicates that the agent sends an agreement to an seller agent which agreed on a bid.
	itemBought(Item,Seller,Price):	Indicates that both parties comitted to trading the item, for the specified price.
*******************************************************************************************************************************/
+!organiseAuction(Item,MinPrice,MaxPrice,StepSize,RoundTimeout) :  not organisingAuction(Item) <-
	+organisingAuction(Item);
	+auctionInfo(Item,MinPrice,0,[]); /* The item, the currentbidprice and roundnr and sellers of the previous round */
	.print("Organising auction for item(",Item,") MinPrice(",MinPrice,") MaxPrice(",MaxPrice,") StepSize(",StepSize,") RoundTimeout(",RoundTimeout,")."); 
	+continueAuction(Item);
	while(continueAuction(Item))
	{
		/* Find all sellers for this item, this makes the auction dynamic. */
		.findall(X,matchingOffer(Item,X),Sellers); 
		if(.length(Sellers) < 1){.fail;} 		 	
		/* Retrieve auctioninfo from belief base, else fail.*/
		?auctionInfo(Item,PossibleCurrentPrice,CurrentRound,PreviousSellers); 
		-auctionInfo(Item,PossibleCurrentPrice,CurrentRound,PreviousSellers)[source(self)];
		//If there are new sellers, start the round at MinPrice, to guarentee lowest price.
		if(.length(Sellers) > .length(PreviousSellers))
		{
			CurrentPrice = MinPrice;
		}
		else
		{
			CurrentPrice = PossibleCurrentPrice;
		}
		
		!doAuctionRound(Item,CurrentPrice,Sellers,RoundTimeout);
		
		
		
		/*Retrieve list of sellers that replyd with an agreement.*/
		.findall(Y,replyOnAuctionBid(Y,Item,CurrentPrice,agree),SellersAgreed);
		
		/*There is at least 1 agree*/
		if( .length(SellersAgreed) > 0 )
		{
			/*reply on all the agreements.*/
			for(.member(Seller, SellersAgreed))
			{
				/* Send confirmation of the agree to one of the sellers */
				if(not sendConfirmAgreementAgree(Item,CurrentPrice))
				{
					.print("Sending confirment agree for price ", CurrentPrice);
					
					+sendConfirmAgreementAgree(Item,CurrentPrice);
					.send(Seller,tell,confirmAgreement(Item,CurrentPrice,agree));
					+itemBought(Item,Seller,CurrentPrice);
				}
				else
				{
					.send(Seller,tell,confirmAgreement(Item,CurrentPrice,refuse));
				}
			}
		
			-sendConfirmAgreementAgree(Item,Price)[source(self)];
			-continueAuction(Item)[source(self)];
		}
		/* No sellers agreed upon deal */
		else
		{
			if(CurrentPrice == MaxPrice)
			{
				//quit
				-continueAuction(Item)[source(self)];
			}
			/* otherwise continue.*/
			else
			{
				+auctionInfo(Item,CurrentPrice+StepSize,CurrentRound+1,Sellers);
			}
		}
		
		
		.abolish(replyOnAuctionBid(_,Item,CurrentPrice,_));
		
	}
	.print("abolishing beliefs for auction");
	.abolish(auctionInfo(Item,_,_,_)[source(self)]);
	.abolish(continueAuction(Item));
	.abolish(replyOnAuctionBid(_,Item,_,_));
	.abolish(sendConfirmAgreementAgree(Item,_));	
	-organisingAuction(Item)[source(self)].

-!organiseAuction(Item,MinPrice,MaxPrice,StepSize,RoundTimeout) :  true <-
	-organisingAuction(Item)[source(self)];
	.abolish(auctionInfo(Item,_,_,_));
	.abolish(continueAuction(Item));
	.abolish(replyOnAuctionBid(_,Item,_,_));	
	.abolish(sendConfirmAgreementAgree(Item,_));
	.print("Failed to organize auction.").
	
/*******************************************************************************************************************************
	DoAuctionRound : To advance one round in the auction.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item to auction.
	CurrentPrice: The price of this bid on the item this round.
	Sellers 	: The sellers to send your bid to.
	RoundTimeout: The maximum time to wait on response before continuing.
	----------------------------------------------------------------------------------------------------------------------
	Beliefs added:
	doingAuctionRound(Item): Indicates the agent is performing the doAuctionRound goal for specified item.
*******************************************************************************************************************************/
+!doAuctionRound(Item,CurrentPrice,Sellers,Timeout) : organisingAuction(Item) & not doingAuctionRound(Item) <-
	+doingAuctionRound(Item);
	.print("Doing auction round for Item(",Item,") CurrentPrice(",CurrentPrice,") Sellers(",Sellers,") Timeout(",Timeout,").");
	!sendAuctionBids(Item,CurrentPrice,Sellers);
	/* Wait for all replies, or timeout, do not fail if timeout passes */	
	.wait({+allAuctionBidRepliesReceived(Item,CurrentPrice)[source(self)]},Timeout,EventTime); 
	.abolish(allAuctionBidRepliesReceived(Item,CurrentPrice));
	.abolish(waitingOnAuctionBidReply(Item,CurrentPrice,_));
	.abolish(auctionBidSend(Item,CurrentPrice,_));
	-doingAuctionRound(Item)[source(self)].

-!doAuctionRound(Item,CurrentPrice,Sellers,Timeout) : true <-
	.abolish(allAuctionBidRepliesReceived(Item,CurrentPrice));
	.abolish(waitingOnAuctionBidReply(Item,CurrentPrice,_));
	.abolish(auctionBidSend(Item,CurrentPrice,_));
	-doingAuctionRound(Item)[source(self)];
	.print("Failed auction round!").
/*******************************************************************************************************************************
	SendAuctionBids : Sends bids to the sellers.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item to bid on.
	Price		: The price of this bid.
	Sellers 	: The sellers to send your bid to.
	----------------------------------------------------------------------------------------------------------------------
	Beliefs added:
	sendingAuctionBids(Item)	: Indicates wether the agent is performing the goal sendAuctionBids for specified Item.
	waitingOnAuctionBidReply(Item,Price,Seller)	: Indicates if the agent is expecting a reply from the Seller for an auction bid.
	auctionBidSend(Item,Price,Seller):	Indicates the agent has send an auction bid.
*******************************************************************************************************************************/	
+!sendAuctionBids(Item,Price,Sellers) : organisingAuction(Item) & doingAuctionRound(Item) & not sendingAuctionBids(Item) <-
	+sendingAuctionBids(Item);
	for( .member( Seller, Sellers ) )
	{
		+waitingOnAuctionBidReply(Item,Price,Seller);
		+auctionBidSend(Item,Price,Seller);
		.print( "auction bid send: Seller(", Seller, ") Item(", Item, ") Price(",Price,")." );
		.send( Seller, tell, auctionBid(Item, Price ) );
	};
	-sendingAuctionBids(Item)[source(self)].

-!sendAuctionBids(Item,Price,Sellers) : organisingAuction(Item) & doingAuctionRound(Item) <-
	.abolish(waitingOnAuctionBidReply(Item,Price,Seller));
	.abolish(auctionBidSend(Item,Price,_));
	-sendingAuctionBids(Item)[source(self)].
	
/*******************************************************************************************************************************
	SendAuctionBidReply : Sends a reply on an auction bid.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item to reply on.
	Price		: The price of the bid offered.
	Buyer 		: The trader who wants to buy this item.
	Timeout		: The maximum time to wait for a confirmation received.(Only when an agree reply is send)
	----------------------------------------------------------------------------------------------------------------------
	Beliefs added:
	waitingOnAgreeConfirmation(Item,Price,Buyer):	Indicates this seller agent is waiting on an confirmation from the buyer.
	auctionReplyAgreeSend(Item,Price,Buyer):	Indicates an auctionReply with agree is send to the buyer.
*******************************************************************************************************************************/		
+!sendAuctionBidReply(Item,Price,Buyer,Timeout) : selling(Item,PriceToSell) & registeredOffer(Item) <-
	if( Price >= PriceToSell & not auctionReplyAgreeSend( Item, _, _ ) )		/* Note: use "not" to check if something isn't in the database, ~ for explicit false */
	{
		.print( "Agree to offer: ", Item, " ", Price );
		+waitingOnAgreeConfirmation(Item,Price,Buyer);
		+auctionReplyAgreeSend(Item,Price,Buyer);
		.send(Buyer, tell, replyOnAuctionBid( Item, Price, agree ) );
		.wait({+confirmAgreement(Item,Price,Result)[source(Buyer)]},Timeout);
		-confirmAgreement(Item,Price,Result)[source(Buyer)];
		if(Result == agree){+itemSold(Item,Price,Buyer);};
	}
	else
	{
		/* Here no message is expected back */
		.print( "Refuse to offer: ", Item, " ", Price );
		.send( Buyer, tell, replyOnAuctionBid( Item, Price, refuse ) );
	}
	.

-!sendAuctionBidReply(Item,Price,Buyer,Timeout) : selling(Item,PriceToSell) & registeredOffer(Item) <-
	-waitingOnAgreeConfirmation(Item,Price,Buyer)[source(self)];
	-auctionReplyAgreeSend(Item,Price,Buyer)[source(self)].	

	
	
/*******************************************************************************************************************************
	 BELIEFS TRIGGERED
*******************************************************************************************************************************/

/*******************************************************************************************************************************
	AuctionBid : Received a bid from a trader who wants to buy an item.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item where is bid on.
	Price		: The price of the bid offered.
*******************************************************************************************************************************/			
+auctionBid(Item,Price)[source(Buyer)] <-
	!sendAuctionBidReply(Item,Price,Buyer,2000);
	-auctionBid( Item, Price )[source( Buyer )].

/*******************************************************************************************************************************
	ReplyOnAuctionBid : Received a reply on an auction bid from a trader who wants to sell an item.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item where is bid on.
	Price		: The price of the bid offered.
	Result		: Whether the trader wants to buy the item, either 'agree' or 'refuse'.
	----------------------------------------------------------------------------------------------------------------------
	Beliefs added:
	replyOnAuctionBid(Seller,Item,Price,Result): Indicates that Seller has replyd on an auction bid of given item and price, with
												 Result being either 'agree' of 'refuse'.
*******************************************************************************************************************************/	
+replyOnAuctionBid(Item,Price,Result)[source(Seller)] : waitingOnAuctionBidReply(Item,Price,Seller) & auctionBidSend(Item,Price,Seller) <-
	-waitingOnAuctionBidReply(Item,Price,Seller)[source(self)];
	/* Remove the update from source seller, and instead add the same belief but now source self, and seller as information */
	-replyOnAuctionBid(Item,Price,Result)[source(Seller)]; 	
	+replyOnAuctionBid(Seller,Item,Price,Result); 	
	TotalReplysSoFar = .count(replyOnAuctionBid(_,Item,Price,_)); /* So now we can count the number of replys */
	TotalAuctionBidsSend = .count(auctionBidSend(Item,Price,_));
	//+totalReplysSoFar(.count(replyOnAuctionBid(_,Item,Price,_))); 
	//+totalAuctionBidsSend(.count(auctionBidSend(Item,Price,_)));  /* And compare it to the number of bids send */
	if(TotalReplysSoFar == TotalAuctionBidsSend)
	{	
		+allAuctionBidRepliesReceived(Item,Price);
	}
	.
	
/*******************************************************************************************************************************
	ConfirmAgreement : Received a reaction on am agreement reply on an auction bid, whether the buyer agrees with your reply.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item where is bid on.
	Price		: The price of the trade offered.
	Result		: Whether the trader wants to buy the item, either 'agree' or 'refuse'.
*******************************************************************************************************************************/	
+confirmAgreement(Item,Price,Result)[source(Buyer)] : waitingOnAgreeConfirmation(Item,Price,Buyer) & auctionReplyAgreeSend(Item,Price,Buyer) <-
	-auctionReplyAgreeSend(Item,Price,Buyer);
	-waitingOnAgreeConfirmation(Item,Price,Buyer);
	.print("Received a confirm Agreement",Result).

/*******************************************************************************************************************************
	MatchingOfferRemoved : Received from the maintainer, if an offer matching a request of this agent is removed.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item of the offer.
	Seller		: The Seller that has removed his offer.
*******************************************************************************************************************************/			
+matchingOfferRemoved(Item,Seller)[source(Maintainer)] : maintainer(Maintainer,_) <-
	-matchingOffer(Item,Seller)[source(self)];
	-matchingOfferRemoved(Item,Seller)[source(Maintainer)].
	
/*******************************************************************************************************************************
	MatchingOfferAdded : Received from the maintainer, if an offer matching a request of this agent is added.
	----------------------------------------------------------------------------------------------------------------------
	Parameters:
	Item 		: The item of the offer.
	Seller		: The Seller that has removed his offer.
*******************************************************************************************************************************/
+matchingOfferAdded(Item,Seller)[source(Maintainer)] : maintainer(Maintainer,_) <-
	+matchingOffer(Item,Seller);
	-matchingOfferAdded(Item,Seller)[source(Maintainer)].
